package engine;

import java.text.DecimalFormat;
import java.util.ArrayList;

public class DenseVectorTI extends AbstractVectorTI<DenseVectorTI> {

    private Double[] values;

    public DenseVectorTI(Integer size) {
        super(size);
        values = new Double[size];
    }

    @Override
    public Integer size() {
        return super.size;
    }

    @Override
    public AbstractVectorTI clone() {
        DenseVectorTI copy = new DenseVectorTI(super.size);

        for (int i = 0; i < values.length; i++) {
            copy.put(i, values[i]);
        }

        return copy;
    }

    @Override
    public void put(Integer wordID, Double value) {
        values[wordID] = value;
    }

    @Override
    public Double get(Integer wordID) {
        return values[wordID];
    }

    @Override
    public Double norm() {
        double sum = 0d;

        for (int i = 0; i < values.length; i++) {
            sum += values[i] * values[i];
        }

        return Math.sqrt(sum);
    }

    @Override
    public AbstractVectorTI normalize() {
        DenseVectorTI normalizedVector = new DenseVectorTI(super.size);

        Double norm = norm();

        //Si la norme est nulle, on retourne le vecteur non modifié
        if (norm == 0d) {
            return clone();
        }

        for (int i = 0; i < values.length; i++) {
            normalizedVector.put(i, values[i] / norm);
        }

        return normalizedVector;
    }

    @Override
    public Double distanceManhattan(DenseVectorTI v1, DenseVectorTI v2) {
        Double sum = 0d;

        for (int i = 0; i < values.length; i++) {
            sum += Math.abs(v1.get(i) - v2.get(i));
        }

        return sum;
    }

    @Override
    public Double distanceEuclidienne(DenseVectorTI v1, DenseVectorTI v2) {
        Double sum = 0d;
        Double currentDifference;

        for (int i = 0; i < values.length; i++) {
            currentDifference = Math.abs(v1.get(i) - v2.get(i));
            sum += currentDifference * currentDifference;
        }

        return Math.sqrt(sum);
    }

    @Override
    public Double distanceMinkowski(DenseVectorTI v1, DenseVectorTI v2, Integer parameter) {
        Double sum = 0d;
        Double currentDifference;

        for (int i = 0; i < values.length; i++) {
            currentDifference = Math.abs(v1.get(i) - v2.get(i));
            sum += Math.pow(currentDifference, parameter);
        }

        return Math.pow(sum, 1 / parameter);
    }

    @Override
    public AbstractVectorTI average(ArrayList<DenseVectorTI> vectors) {
        Integer vectorsCount = vectors.size();
        if (vectorsCount == 0) {
            return null;
        }

        DenseVectorTI averageVector = new DenseVectorTI(super.size);
        Double currentIdAvg;

        for (int i = 0; i < values.length; i++) {

            currentIdAvg = 0d;
            for (DenseVectorTI v : vectors) {
                currentIdAvg += v.get(i);
            }

            averageVector.put(i, currentIdAvg / vectorsCount);
        }

        return averageVector;
    }

    @Override
    public String toString() {
        DecimalFormat twoDecimals = new DecimalFormat("#.##");

        String print = "";

        for (int i = 0; i < values.length; i++) {
            print += twoDecimals.format(values[i]) + "; ";
        }

        return print;
    }

    @Override
    public String toString(ArrayList<String> voc) {
        DecimalFormat twoDecimals = new DecimalFormat("#.##");

        String print = "";

        for (int i = 0; i < values.length; i++) {
            if (values[i] != 0d) {
                print += voc.get(i) + " : " + twoDecimals.format(values[i]) + "; ";
            }
        }

        return print;
    }

    //N'affiche que les mots avec un poids supérieur à weightMin
    @Override
    public String toShortString(ArrayList<String> voc, double weightMin) {
        DecimalFormat twoDecimals = new DecimalFormat("#.##");

        String print = "";

        for (int i = 0; i < values.length; i++) {
            if (values[i] >= weightMin) {
                print += voc.get(i) + " : " + twoDecimals.format(values[i]) + "; ";
            }
        }

        return print;
    }
}
